/* Includes ------------------------------------------------------------------*/
#include "string.h"
#include "nheap.h"
#include "nheapConf.h"

/* typedef -----------------------------------------------------------*/
/* define ------------------------------------------------------------*/
/* macro --------------------------------------------------------------*/
/* variables ----------------------------------------------------------*/
uint32_t _heapUsed = 0, _heapMaxUsed = 0;
uint32_t _nheapPool[NEHEAP_POOL_SIZE / 4];

#if (NEHEAP_POOL_SIZE / NEHEAP_BLOCK_SIZE) <= 255
uint8_t  _nheapBlocks[NEHEAP_POOL_SIZE / NEHEAP_BLOCK_SIZE];
#else
uint16_t  _nheapBlocks[NEHEAP_POOL_SIZE / NEHEAP_BLOCK_SIZE];
#endif

/* function prototypes ------------------------------------------------*/
__attribute__((weak)) void NEHeapHook_Lack(void){}
__attribute__((weak)) void NEHeapHook_Debris(void){}

void *NEHeap_Malloc(size_t size);
void NEHeap_Free(void *pointer);
void *NEHeap_Realloc(void *pointer, size_t size);
	
#define NHEAP_COUNTER_CHANGE(count)			\
	{										\
		_heapUsed += count;					\
		if(_heapMaxUsed < _heapUsed)		\
		{	_heapMaxUsed = _heapUsed;	}	\
	}
/*********************************************************************************************

	NEHeap_Malloc

*********************************************************************************************/
void *NEHeap_Malloc(size_t size)
{
    int i = 0;
  
    DISABLE_ALL_INTERRPUTS();
    
    uint8_t *pool = (uint8_t *)_nheapPool;         

    /* calculate the count of block which request */
    int countBlockRequest = ((size % NEHEAP_BLOCK_SIZE) == 0) ? (size / NEHEAP_BLOCK_SIZE) : (size / NEHEAP_BLOCK_SIZE + 1); 
    int tempCounter = 0;
    int index;

    /* the remain block is not enough */
    if (_heapUsed >= sizeof(_nheapBlocks))
    {
		NEHeapHook_Lack();
        return NULL;
    }

    /* look for continuous idle block */
    for (index = 0; index < sizeof(_nheapBlocks); index++)
    {
        tempCounter = (_nheapBlocks[index] == 0) ? (tempCounter + 1) : 0;
        if (tempCounter == countBlockRequest)
        {   break;  }
    }

    /* return the result */
    if (index != sizeof(_nheapBlocks))
    {
        NHEAP_COUNTER_CHANGE(countBlockRequest);                                 
        
        for (i=0; i <countBlockRequest; i++)
        {   _nheapBlocks[index - countBlockRequest + i + 1] = countBlockRequest;  }      

        ENABLE_ALL_INTERRPUTS();
        return (void *)(pool + (index - countBlockRequest + 1) * NEHEAP_BLOCK_SIZE);
    }
    else
    {
        NEHeapHook_Debris();
        ENABLE_ALL_INTERRPUTS();
        return NULL;
    }
}
/*********************************************************************************************

	NEHeap_Realloc

*********************************************************************************************/
void *NEHeap_Realloc(void *pointer, size_t size)
{
    NEHeap_Free(pointer);
    return NEHeap_Malloc(size);
}
/*********************************************************************************************

	NEHeap_Free

*********************************************************************************************/
void NEHeap_Free(void *pointer)
{
    DISABLE_ALL_INTERRPUTS();

    uint16_t index = ((uint32_t)pointer - (uint32_t)_nheapPool) / NEHEAP_BLOCK_SIZE; 
    uint16_t len = _nheapBlocks[index];                                                   
    NHEAP_COUNTER_CHANGE(-len);

    //memset(pointer, 0, len * NEHEAP_BLOCK_SIZE);
    
    for (uint16_t i = 0; i < len; i++)
    {   _nheapBlocks[index + i] = 0;  } // 在管理单元中释放该位

    ENABLE_ALL_INTERRPUTS();
}
